package com.itany.mall.factory;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

// 对象工厂
// 工厂启动时, 读取配置文件(从类加载目录加载一个叫"objects.properties"的文件)
// 获取要创建哪些类的对象的配置信息
// 将目标类的Class对象存入容器
// 工厂提供公共方法, 来获取容器中的对象
// 当进行对象的获取时, 根据情况将目标对象创建出来
public class ObjectFactory {

	// 准备容器
	private static final Map<String, Object> OBJECTS;
	private static final Map<String, Class> CLASSES;

	// 工厂启动时进行初始化操作
	// 1. 读取配置文件
	//    将配置文件放到一个容易获取的地方: 类加载目录
	// 2. 创建对象
	// 修改: 当工厂启动时, 不创建对象, 而是存储类的Class对象
	// 将对象的创建时机向后延迟, 当从工厂获取对象时, 选判断工厂中有没有该对象
	// 如果没有目标对象, 则进行对象的创建, 并存入到容器中
	static {
		OBJECTS = new HashMap<>();
		CLASSES = new HashMap<>();

		try {
			Properties properties = new Properties();
			InputStream is = ObjectFactory.class.getClassLoader()
					.getResourceAsStream("objects.properties");
			properties.load(is);

			for (Map.Entry entry : properties.entrySet()) {
				String key = (String) entry.getKey();
				String className = (String) entry.getValue();

				System.out.println(key + " ---> " + className);

				Class c = Class.forName(className);
				CLASSES.put(key, c);
				// OBJECTS.put(key, c.newInstance());
			}

		} catch (Exception e) {
			e.printStackTrace();
			// 如果发生异常, 说明工厂初始化失败
			// 程序中使用工厂就会有问题, 从而导致整个程序都有问题
			// 程序应当终止, 让程序员检查并排除问题
			// 静态代码块中, 能被throw关键字操作的对象只有一个:
			throw new ExceptionInInitializerError("工厂初始化失败");
		}

	}

	// 公共的获取对象的方法
	public static Object getObject(String key) {
		Object obj = OBJECTS.get(key);
		try {
			if (obj == null) {
				Class c = CLASSES.get(key);
				obj = c.newInstance();
				OBJECTS.put(key, obj);
			}
		} catch (Exception e) {
			e.printStackTrace();
			// 当发生异常, 则说明从工厂的容器中获取对象失败
			// 从而导致程序运行存在安全隐患
			// 应当让程序终止, 让程序员检查并排除问题
			throw new RuntimeException("从工厂获取对象 " + key + " 失败", e);
		}
		return obj;
	}

}
